﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;

namespace YueRu.Common
{
    /// <summary>
    /// 有关HTTP请求的辅助类
    /// </summary>
    public class HttpWebResponseUtility
    {
        private static readonly string DefaultUserAgent =
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">请求的URL</param>
        /// <param name="timeout">请求的超时时间</param>
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>
        /// <returns></returns>
        public static HttpWebResponse CreateGetHttpResponse(string url, int? timeout, string userAgent,
            CookieCollection cookies)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "GET";
            request.UserAgent = DefaultUserAgent;
            if (!string.IsNullOrEmpty(userAgent))
            {
                request.UserAgent = userAgent;
            }
            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }
            return request.GetResponse() as HttpWebResponse;
        }


        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">请求的URL</param>
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>
        /// <param name="timeout">请求的超时时间</param>
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>
        /// <returns></returns>
        public static HttpWebResponse CreatePostHttpResponse(string url, IDictionary<string, string> parameters,
            int? timeout, string userAgent, Encoding requestEncoding, CookieCollection cookies)
        {
            return CreatePostHttpResponse(url, parameters, timeout, userAgent, requestEncoding, cookies,
                HttpContentTypeEnum.xwwwfrom);
        }

        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">请求的URL</param>
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>
        /// <param name="timeout">请求的超时时间</param>
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>
        /// <returns></returns>
        public static HttpWebResponse CreatePostHttpResponse(string url, IDictionary<string, string> parameters,
            int? timeout, string userAgent, Encoding requestEncoding, CookieCollection cookies,
            HttpContentTypeEnum contenttype)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request = null;
            //如果是发送HTTPS请求
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback =
                    new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            request.Method = "POST";

            switch (contenttype)
            {
                case HttpContentTypeEnum.xwwwfrom:
                    request.ContentType = "application/x-www-form-urlencoded";
                    break;
                case HttpContentTypeEnum.textxml:
                    request.ContentType = "text/xml";
                    break;
                default:
                    request.ContentType = "application/x-www-form-urlencoded";
                    break;
            }

            if (!string.IsNullOrEmpty(userAgent))
            {
                request.UserAgent = userAgent;
            }
            else
            {
                request.UserAgent = DefaultUserAgent;
            }

            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }

            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }


            //如果需要POST数据
            if (!(parameters == null || parameters.Count == 0))
            {
                StringBuilder buffer = new StringBuilder();
                int i = 0;
                foreach (string key in parameters.Keys)
                {
                    if (i > 0)
                    {
                        buffer.AppendFormat("&{0}={1}", key, parameters[key]);
                    }
                    else
                    {
                        buffer.AppendFormat("{0}={1}", key, parameters[key]);
                    }
                    i++;
                }
                byte[] data = requestEncoding.GetBytes(buffer.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }

            HttpWebResponse res = request.GetResponse() as HttpWebResponse;
            return res;
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain,
            SslPolicyErrors errors)
        {
            return true; //总是接受
        }


        public enum HttpContentTypeEnum
        {
            //       x-www-form-urlencoded=0,
            xwwwfrom = 0,
            textxml = 1,
            //json = 2
        }


        /// <summary>
        /// HTTP请求提交JSON数据
        /// </summary>
        /// <param name="method"></param>
        /// <param name="url"></param>
        /// <param name="postData"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public string WebHttpRequest(Method method, string url, string postData,
            IDictionary<string, string> headers = null)
        {
            string ret = _WebRequest(method, url, postData, headers);
            return ret;
        }

        public enum Method
        {
            GET,
            POST,
            PUT,
            DELETE
        };

        private string _WebRequest(Method method, string url, string postData,
            IDictionary<string, string> headers = null)
        {
            HttpWebRequest webRequest = null;
            StreamWriter requestWriter = null;
            string responseData = "";

            webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
            webRequest.ServicePoint.ConnectionLimit = 10000;
            //webRequest.KeepAlive = false;
            //webRequest.ProtocolVersion = HttpVersion.Version10;

            webRequest.Method = method.ToString();
            webRequest.Accept = "*/*";
            webRequest.Headers.Add("Accept-Language", "zh-cn");
            webRequest.UserAgent = "EP API Client";
            webRequest.ServicePoint.Expect100Continue = false;
            webRequest.ContentType = "application/json";

            if (headers != null)
            {
                foreach (var dic in headers)
                {
                    webRequest.Headers.Add(dic.Key, dic.Value);
                }
            }
            ;
            // webRequest.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";

            //webRequest.ContentType = "text/json";

            if (method == Method.POST)
            {
                webRequest.ContentType = "application/json";

                try
                {
                    requestWriter = new StreamWriter(webRequest.GetRequestStream());
                    requestWriter.Write(postData);
                }
                catch
                {
                    webRequest.Abort();
                    webRequest = null;
                    throw;
                }
                finally
                {
                    if (requestWriter != null)
                    {
                        requestWriter.Close();
                        requestWriter = null;
                    }
                }
            }

            try
            {
                responseData = _WebResponseGet(webRequest);
            }
            catch
            {
                throw;
            }
            finally
            {
                webRequest.Abort();
                webRequest = null;
            }

            return responseData;
        }

        private string _WebResponseGet(HttpWebRequest webRequest)
        {
            StreamReader responseReader = null;
            string responseData = "";
            try
            {
                responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
                responseData = responseReader.ReadToEnd();
            }
            catch (WebException ee)
            {
                if (ee.Message == "基础连接已经关闭: 接收时发生错误。")
                {
                    responseData = "{}";
                    return responseData;
                }

                if (ee.Response == null)
                    throw new ClientWebException("远程接口返回错误：" + "<br>" + webRequest.RequestUri.ToString() + ee.Message,
                        ee.StackTrace);


                HttpWebResponse req = (HttpWebResponse) ee.Response;
                responseReader = new StreamReader(req.GetResponseStream());
                responseData = responseReader.ReadToEnd();
                System.Text.RegularExpressions.Regex reg =
                    new Regex("<Message>(.*?)</Message><StackTrace>(.*?)</StackTrace>",
                        RegexOptions.IgnoreCase | RegexOptions.Singleline);
                if (reg.IsMatch(responseData))
                {
                    Match m = reg.Match(responseData);
                    ClientWebException exp =
                        new ClientWebException(
                            "远程接口返回错误：" + m.Groups[1].Value + "<br>" + webRequest.RequestUri.ToString(),
                            m.Groups[2].Value);
                    throw exp;
                }
                else
                {
                    throw new ClientWebException("远程接口返回错误：" + ee.Message + "<br>" + webRequest.RequestUri.ToString(),
                        ee.StackTrace);
                }
            }
            finally
            {
                //webRequest.GetResponse().GetResponseStream().Close();
                if (responseReader != null)
                    responseReader.Close();
                responseReader = null;
            }

            return responseData;
        }


        public class ClientWebException : Exception
        {
            private string _stackTrace = "";

            public override string StackTrace
            {
                get { return _stackTrace; }
            }

            public ClientWebException(string errMsg, string StackTrace)
                : base(errMsg)
            {
                _stackTrace = StackTrace;
            }
        }
    }
}